from typing import List
import re

import requests
from bs4 import BeautifulSoup
from bs4.element import Tag
from fake_useragent import UserAgent

from db.utils import DbUtils
from db.utils import TaskObject


class ScraperCodeforces:
    """ Парсер для сервиа codeforces """

    def __init__(self):
        self.LINK_TO_LIST_OF_ALL_TASKS = 'https://codeforces.com/problemset?order=BY_SOLVED_DESC'


    def update_list_of_tasks(self) -> None:
        """ Обновляем список задач """

        task_list_from_resource = self.parsing_tasks_from_resource()
        DbUtils().add_list_of_tasks(task_list_from_resource)


    def get_page_from_link(self, link: str) -> BeautifulSoup:
        """ Получаем страницу по ссылке """

        headers = {'User-Agent': UserAgent().chrome}
        response = requests.get(link, headers=headers)
        if response.status_code != 200: raise ValueError('Код ответа не 200')
        page = BeautifulSoup(response.text, 'lxml')
        return page


    def get_task_information(self, task: Tag) -> TaskObject:
        """ Получаем информацию о задаче """

        def get_link(task: Tag) -> str:
            """ Получаем ссылку задачи """

            domen = 'https://codeforces.com'
            path = task.find_all('td')[1].find('a').get('href').strip()
            link = domen + path
            return link


        def get_number(task: Tag) -> str:
            """ Получаем номер задачи """

            number = task.find_all('td')[0].text.strip()
            return number


        def get_name(task: Tag) -> str:
            """ Получаем название задачи """

            name = task.find_all('td')[1].find('div').text.strip()
            return name


        def get_topics(task) -> List[str]:
            """ Получаем темы задачи """

            topics = task.find_all('td')[1].find_all('div')[1].text
            return [topic.strip() for topic in topics.split(',')]


        def get_complexity(task) -> int:
            """ Получаем сложность задачи """

            try:
                complexity = int(task.find('span', title='Difficulty').text)
                return complexity
            except AttributeError:
                return 0


        def get_number_of_solutions(task) -> int:
            """ Получаем количество людей решивших задачу """

            try:
                number_of_solutions = task.find(
                    'a', title='Participants solved the problem'
                ).text
                number_of_solutions = int(re.findall('\d+', number_of_solutions)[0])
                return number_of_solutions
            except AttributeError:
                return 0


        # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

        link = get_link(task)
        number = get_number(task)
        name = get_name(task)
        topics = get_topics(task)
        complexity = get_complexity(task)
        number_of_solutions = get_number_of_solutions(task)
        task = TaskObject(
            link=link,
            number=number,
            name=name,
            topics=topics,
            complexity=complexity,
            number_of_solutions=number_of_solutions,
        )
        return task


    def get_task_list_from_page(self, page: BeautifulSoup) -> List[TaskObject]:
        """ Получаем список задач со страницы """

        list_of_tasks_from_page = []
        task_table = page.find('table', class_='problems')
        list_of_tasks = task_table.find_all('tr')[1:]

        for task in list_of_tasks:
            task_information = self.get_task_information(task)
            list_of_tasks_from_page.append(task_information)

        return list_of_tasks_from_page


    def get_number_of_pages_with_tasks(self, page: BeautifulSoup) -> str:
        """ Получаем количество страниц с задачами """

        number_of_pages_with_tasks = page.find_all(
            'span', pageindex=True
        )[-1].text
        number_of_pages_with_tasks = int(number_of_pages_with_tasks.strip())
        return number_of_pages_with_tasks


    def parsing_tasks_from_resource(self) -> List[TaskObject]:
        """ Парсим задачи с ресурса """

        tasks_from_resource = []
        page = self.get_page_from_link(self.LINK_TO_LIST_OF_ALL_TASKS )
        number_of_pages_with_tasks = self.get_number_of_pages_with_tasks(page)

        for page_number in range(1, number_of_pages_with_tasks + 1):

            link = f'https://codeforces.com/problemset/page/{page_number}?order=BY_SOLVED_DESC'
            page = self.get_page_from_link(link)
            tasks_from_page = self.get_task_list_from_page(page)
            [tasks_from_resource.append(task) for task in tasks_from_page]

        return tasks_from_resource

